<?php


namespace app\common\components;


use app\common\exception\ApiException;

require_once ROOT_PATH . 'extend/wxpay/WxPayConfig.php';

/**
 * 微信支付类
 * Class Wxpay
 * @package app\common\components
 */
class Wxpay extends BaseComponents
{
    /**
     * 调用第三方类库 发起支付
     * 微信and小程序支付
     * @param array $option 额外的参数 必传 out_trade_no notify_url option
     * @return mixed
     * @throws \WxPayException
     */
    static function GetJsApiParameters($payData=[]){
        //获取小程序信息
        $config = new \WxPayConfig();
        $config->setJsapiTrade();

        //统一公共入参
        $input = self::_init($payData,$config);
        //个性入参
        $input->SetTrade_type("JSAPI");
        if(empty($payData['openid'])){
            throw new ApiException("缺少必要参数Openid");
        }
        $input->SetOpenid($payData['openid']);
        $order = \WxPayApi::unifiedOrder($config,$input);

        //增加返回失败状态
        if (!empty($order['return_code']) && $order['return_code'] == 'FAIL') {
            throw new ApiException($order['return_msg']);
        }
        //result_code不为SUCCESS则为失败
        if (empty($order['result_code']) || $order['result_code'] != 'SUCCESS') {
            throw new ApiException($order['err_code_des']??"系统错误");
        }
        // "{"appId":"wxecdf617b97e11e00","nonceStr":"behdpjcmhq8zpvqdy65qmma122kkjs4c","package":"prepay_id=wx151508097789164d809cfe0d9fe7800000","signType":"MD5","timeStamp":"1618470494","paySign":"976390EED5799155E19655F6DCF9F8C5"}"
        //处理需要返回给APP的数据
        $result =[
            'appId'     => $order['appid'],//应用APPID
            'timeStamp' =>time(),
            //'mch_id'     => $order['mch_id'],//商户号
            'nonceStr'     => $order['nonce_str'],//随机字符串
            'package'   => 'prepay_id='.$order['prepay_id'],//数据包
            'signType'   => $config->GetSignType(),
        ];
        $result['paySign'] = self::getSign($result,$config);
        return $result;
    }

    /**
     * 支付订单查询
     * @param $out_trade_no
     * @return \成功时返回，其他抛异常
     * @throws \WxPayException
     */
    static function orderQuery($out_trade_no){
        $input = new \WxPayOrderQuery();
        //获取小程序信息
        $config = new \WxPayConfig();
        $config->setJsapiTrade();
        $input->SetOut_trade_no($out_trade_no);
        $order = \WxPayApi::orderQuery($config,$input);
        //增加返回失败状态
        if (!empty($order['return_code']) && $order['return_code'] == 'FAIL') {
            throw new ApiException($order['return_msg']);
        }
        //result_code不为SUCCESS则为失败
        if (empty($order['result_code']) || $order['result_code'] != 'SUCCESS') {
            throw new ApiException($order['err_code_des']??"系统错误");
        }
        return $order;
    }

    /**
     * 微信退款
     */
    static function refund($out_trade_no,$total_fee,$refund_fee,$out_refund_no){
        $config = new \WxPayConfig();
        $config->setJsapiTrade();
//        $total_fee = $_REQUEST["total_fee"];
        $input = new \WxPayRefund();
        $input->SetOut_trade_no($out_trade_no);
        $input->SetTotal_fee($total_fee);
        $input->SetRefund_fee($refund_fee*100);
        $input->SetOut_refund_no($out_refund_no);
        $input->SetOp_user_id($config->GetMerchantId());
        return \WxPayApi::refund($config,$input);
    }

    /**
     * @param $money
     * @param array $option
     * @param \WxPayConfig $payConfig
     * @return \WxPayUnifiedOrder
     */
    static private function _init($payData=[],$payConfig=[]){
        //默认参数
        $param = array_merge([
            'title'=>'支付test',
            'out_trade_no'=>$payConfig->GetMerchantId().date("YmdHis"),
            'attach'=>'test',
             'notify_url'=>get_host().'/api/paymentNotify/jsapiwxpayNotify',//留空使用默认的回调地址
        ],$payData);

        //②、统一下单
        $input = new \WxPayUnifiedOrder();
        $input->SetBody($param['title']);
        $input->SetAttach($param['attach']);//自定义数据
        $input->SetOut_trade_no($param['out_trade_no']);
        $input->SetTotal_fee($payData['money']*100);
        $input->SetTime_start(date("YmdHis"));//订单开始时间
        //订单失效时间10分钟
        $input->SetTime_expire(date("YmdHis", time() + self::$overdue_time));
        if($param['notify_url']){
            $input->SetNotify_url($param['notify_url']);
        }
        return $input;
    }

    /**
     * 支付生成签名
     * @param \WxPayConfig $values  需要签名的参数
     * @param \WxPayConfig $config  配置对象
     * @author 小聂
     * @since 2020/8/28
     * @return string
     */
    public static function getSign($values,$config) {
        //签名步骤一：按字典序排序参数
        ksort($values);
        $buff = "";
        foreach ($values as $k => $v){
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }
        $string = trim($buff, "&");
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=".$config->GetKey();
        //签名步骤三：MD5加密或者HMAC-SHA256
        if($config->GetSignType() == "MD5"){
            $string = md5($string);
        } else if($config->GetSignType() == "HMAC-SHA256") {
            $string = hash_hmac("sha256",$string ,$config->GetKey());
        } else {
            throw new ApiException("签名类型不支持！");
        }
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }
}